using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Reflection;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Provides the tracking data.
    /// </summary>
    internal class TrackingData
    {
        /// <summary>
        /// Occurs if a tracked property has changed.
        /// </summary>
        public event EventHandler<TrackedPropertyChangedEventArgs> TrackedPropertyChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:TrackingData"/> class.
        /// </summary>
        /// <param name="trackedObject">The tracked object.</param>
        /// <param name="trackedPropertyName">Name of the tracked property.</param>
        public TrackingData(INotifyPropertyChanged trackedObject, string trackedPropertyName) {

            if (trackedObject == null) { throw new ArgumentNullException("trackedObject"); }

            this._trackedObject = trackedObject;
            this._trackedPropertyName = trackedPropertyName;
            this._trackedObject.PropertyChanged += new PropertyChangedEventHandler(TrackedObjectPropertyChanged);

            this._trackedPropertyValue = this.GetTrackedPropertyValue();
        }

        private INotifyPropertyChanged _trackedObject;

        /// <summary>
        /// Gets or sets the tracked object.
        /// </summary>
        /// <value>The tracked object.</value>
        public INotifyPropertyChanged TrackedObject {
            get { return _trackedObject; }
        }

        private object _trackedPropertyValue;

        /// <summary>
        /// Gets or sets the tracked property value.
        /// </summary>
        /// <value>The tracked property value.</value>
        public object TrackedPropertyValue {
            get { return _trackedPropertyValue; }
            private set { _trackedPropertyValue = value; }
        }

        private string _trackedPropertyName;

        /// <summary>
        /// Gets or sets the name of the tracked property.
        /// </summary>
        /// <value>The name of the tracked property.</value>
        public string TrackedPropertyName {
            get { return _trackedPropertyName; }
        }

        /// <summary>
        /// Called when [tracked property changed].
        /// </summary>
        protected void OnTrackedPropertyChanged() {
            if (this.TrackedPropertyChanged != null) {
                this.TrackedPropertyChanged(this, new TrackedPropertyChangedEventArgs(this.TrackedObject, this.TrackedPropertyValue, this.GetTrackedPropertyValue()));
            }
        }

        /// <summary>
        /// Trackeds the object property changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="T:System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        private void TrackedObjectPropertyChanged(object sender, PropertyChangedEventArgs e) {
            if (e.PropertyName == this.TrackedPropertyName) {
                this.OnTrackedPropertyChanged();
                this.TrackedPropertyValue = this.GetTrackedPropertyValue();
            }
        }

        /// <summary>
        /// Gets the tracked property value.
        /// </summary>
        /// <returns></returns>
        private object GetTrackedPropertyValue() {
            object value = null;

            PropertyInfo trackedPropertyInfo = this.TrackedObject.GetType().GetProperty(this.TrackedPropertyName);

            if (trackedPropertyInfo != null) {
                value = trackedPropertyInfo.GetValue(this.TrackedObject, null);
            }

            return value;
        }
    }
}
